﻿using System;
using System.Net;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Silverlight.ControlToolkit.Converters;
using System.Windows.Controls.Primitives;

namespace Silverlight.ControlToolkit.Validator
{

    /// <summary>
    /// This class provides validation service to basic input controls 
    /// </summary>
    public class Validator
    {

        #region Attached Properties

            #region DataType

            public static readonly DependencyProperty DataTypeProperty =
                    DependencyProperty.RegisterAttached("DataType", typeof(DataTypes), typeof(Validator),
                                                        new PropertyMetadata(OnDataTypeChanged));

                /// <summary>
                /// Gets the current datatype associated with the control
                /// </summary>
                /// <param name="d">Dependecy Object / Control</param>
                /// <returns></returns>
                public static DataTypes GetDataType(DependencyObject d)
                {
                    return (DataTypes)d.GetValue(DataTypeProperty);
                }

                /// <summary>
                /// Sets the Data Type property
                /// </summary>
                /// <param name="d">Dependecy Object / Control</param>
                /// <param name="value">Data Type to be set on the control</param>
                public static void SetDataType(DependencyObject d, DataTypes value)
                {
                    d.SetValue(DataTypeProperty, value);
                }

                /// <summary>
                /// Handles changes to the DataType property.
                /// </summary>
                /// <param name="d">Dependecy Object / Control</param>
                /// <param name="e">Event args</param>
                private static void OnDataTypeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
                {
                    
                    if (d is TextBox) //TextBox control
                    {
                        TextBox textBox = d as TextBox;
                        
                        //Remove previous handler if any
                        if ((DataTypes)e.OldValue != DataTypes.None)
                        {
                            textBox.KeyDown -= new KeyEventHandler(textBox_KeyDown);
                            textBox.LostFocus -= new RoutedEventHandler(textBox_LostFocus);
                            textBox.TextChanged -= new TextChangedEventHandler(textBox_TextChanged);
                        }

                        //Add handler if DataType is set
                        if ((DataTypes)e.NewValue != DataTypes.None)
                        {
                            textBox.KeyDown += new KeyEventHandler(textBox_KeyDown);
                            textBox.LostFocus += new RoutedEventHandler(textBox_LostFocus);
                            textBox.TextChanged += new TextChangedEventHandler(textBox_TextChanged);

                        }
                    }
                    else if ((DataTypes)e.NewValue != DataTypes.None && d is Panel && (!SetDataTypeOnAllChild(d)))
                    {
                        ((Panel)d).Loaded += new RoutedEventHandler(Panel_Loaded_DataType);
                    }



                }

                static void Panel_Loaded_DataType(object sender, RoutedEventArgs e)
                {
                    DependencyObject d = sender as DependencyObject;

                    if (d != null)
                    {
                        SetDataTypeOnAllChild(d);
                    }

                    ((Panel)d).Loaded -= new RoutedEventHandler(Panel_Loaded_DataType);


                }

                private static bool SetDataTypeOnAllChild(DependencyObject d)
                {
                    bool results = false;

                    if (d != null)
                    {
                        DataTypes value = Validator.GetDataType(d);

                        foreach (DependencyObject curChild in d.GetVisualChildren())
                        {
                            results = true;

                            if ((curChild is TextBox || curChild is Selector))
                            {
                                Validator.SetDataType(curChild, value);
                            }
                        }
                    }

                    return results;

                }


            #endregion

            #region NegativeAllowed

                public static readonly DependencyProperty NegativeAllowedProperty =
                    DependencyProperty.RegisterAttached("NegativeAllowed", typeof(bool), typeof(Validator),
                                                        new PropertyMetadata(OnNegativeAllowedChanged));

            /// <summary>
            /// Gets the current datatype associated with the control
            /// </summary>
            /// <param name="d">Dependecy Object / Control</param>
            /// <returns></returns>
                public static bool GetNegativeAllowed(DependencyObject d)
            {
                return (bool)d.GetValue(NegativeAllowedProperty);
            }

            /// <summary>
            /// Sets the Data Type property
            /// </summary>
            /// <param name="d">Dependecy Object / Control</param>
            /// <param name="value">Data Type to be set on the control</param>
                public static void SetNegativeAllowed(DependencyObject d, bool value)
            {
                d.SetValue(NegativeAllowedProperty, value);
            }

            /// <summary>
            /// Handles changes to the NegativeAllowed property.
            /// </summary>
            /// <param name="d">Dependecy Object / Control</param>
            /// <param name="e">Event args</param>
            private static void OnNegativeAllowedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
            }

            #endregion

            #region IsRequired

            public static readonly DependencyProperty IsRequiredProperty =
                DependencyProperty.RegisterAttached("IsRequired", typeof(bool), typeof(Validator), null);

            /// <summary>
            /// Gets the current datatype associated with the control
            /// </summary>
            /// <param name="d">Dependecy Object / Control</param>
            /// <returns></returns>
            public static bool GetIsRequired(DependencyObject d)
            {
                return (bool)d.GetValue(IsRequiredProperty);
            }

            /// <summary>
            /// Sets the Data Type property
            /// </summary>
            /// <param name="d">Dependecy Object / Control</param>
            /// <param name="value">Data Type to be set on the control</param>
            public static void SetIsRequired(DependencyObject d, bool value)
            {
                d.SetValue(IsRequiredProperty, value);

                if (d is Panel && (!SetIsRequiredOnAllChild(d)))
                {
                    ((Panel)d).Loaded += new RoutedEventHandler(Panel_Loaded_IsRequired);
                }
            }

            static void Panel_Loaded_IsRequired(object sender, RoutedEventArgs e)
            {
                DependencyObject d = sender as DependencyObject;

                if (d != null)
                {
                    SetIsRequiredOnAllChild(d);
                }

                ((Panel)d).Loaded -= new RoutedEventHandler(Panel_Loaded_IsRequired);

                
            }

            private static bool SetIsRequiredOnAllChild(DependencyObject d)
            {
                bool results = false;

                if (d != null)
                {
                    bool value = Validator.GetIsRequired(d);

                    foreach (DependencyObject curChild in d.GetVisualChildren())
                    {
                        results = true;

                        if ((curChild is TextBox || curChild is Selector))
                        {
                            Validator.SetIsRequired(curChild, value);
                        }
                    }
                }

                return results;
            
            }

            #endregion

            #region DisplayName

            public static readonly DependencyProperty DisplayNameProperty =
                DependencyProperty.RegisterAttached("DisplayName", typeof(string), typeof(Validator), null);

            /// <summary>
            /// Gets the current DisplayName associated with the control
            /// </summary>
            /// <param name="d">Dependecy Object / Control</param>
            /// <returns></returns>
            public static string GetDisplayName(DependencyObject d)
            {
                string displayName = d.GetValue(DisplayNameProperty) as string;

                if (displayName == null) //Return the control name itself
                {
                    string displayControlName = GetDisplayControlName(d);
                    TextBlock displayControl = null;
                    
                    if (displayControlName != null)
                        displayControl = Utilities.GetRootPanel().FindName(displayControlName) as TextBlock;

                    if (displayControl != null)
                        displayName = displayControl.Text.Replace(":", " ").Trim();
                    else
                        displayName = d.GetValue(Control.NameProperty) as string;
                }

                if (displayName != null)
                    return displayName;
                else if (d is Control)
                    return (d as Control).Name;
                else
                    return "Field";
            }

            /// <summary>
            /// Sets the Data Type property
            /// </summary>
            /// <param name="d">Dependecy Object / Control</param>
            /// <param name="value">Data Type to be set on the control</param>
            public static void SetDisplayName(DependencyObject d, string value)
            {
                d.SetValue(DisplayNameProperty, value);
            }

            #endregion

            #region DisplayControlName

            public static readonly DependencyProperty DisplayControlNameProperty =
                DependencyProperty.RegisterAttached("DisplayControlName", typeof(string), typeof(Validator), null);

            /// <summary>
            /// Gets the current DisplayControlName associated with the control
            /// </summary>
            /// <param name="d">Dependecy Object / Control</param>
            /// <returns></returns>
            public static string GetDisplayControlName(DependencyObject d)
            {
                return d.GetValue(DisplayControlNameProperty) as string;

            }

            /// <summary>
            /// Sets the Data Type property
            /// </summary>
            /// <param name="d">Dependecy Object / Control</param>
            /// <param name="value">Data Type to be set on the control</param>
            public static void SetDisplayControlName(DependencyObject d, string value)
            {
                d.SetValue(DisplayControlNameProperty, value);
            }

            #endregion

            #region LastBackground

            private static readonly DependencyProperty LastBackgroundProperty =
                DependencyProperty.RegisterAttached("LastBackground", typeof(Brush), typeof(Validator), null);

            /// <summary>
            /// Gets the current LastBackground associated with the control
            /// </summary>
            /// <param name="d">Dependecy Object / Control</param>
            /// <returns></returns>
            private static Brush GetLastBackground(DependencyObject d)
            {
                return d.GetValue(LastBackgroundProperty) as Brush;

            }

            /// <summary>
            /// Sets the Data Type property
            /// </summary>
            /// <param name="d">Dependecy Object / Control</param>
            /// <param name="value">Data Type to be set on the control</param>
            private static void SetLastBackground(DependencyObject d, Brush value)
            {
                d.SetValue(LastBackgroundProperty, value);
            }

            #endregion

            #region ErrorBackground

            public static readonly DependencyProperty ErrorBackgroundProperty =
                DependencyProperty.RegisterAttached("ErrorBackground", typeof(Brush), typeof(Validator), new PropertyMetadata(new SolidColorBrush(Colors.Red)));

            /// <summary>
            /// Gets the current ErrorBackground associated with the control
            /// </summary>
            /// <param name="d">Dependecy Object / Control</param>
            /// <returns></returns>
            public static Brush GetErrorBackground(DependencyObject d)
            {
                return d.GetValue(ErrorBackgroundProperty) as Brush;

            }

            /// <summary>
            /// Sets the Data Type property
            /// </summary>
            /// <param name="d">Dependecy Object / Control</param>
            /// <param name="value">Data Type to be set on the control</param>
            public static void SetErrorBackground(DependencyObject d, Brush value)
            {
                d.SetValue(ErrorBackgroundProperty, value);

                if (d is Panel && (!SetErrorBackgroundOnAllChild(d)))
                {
                    ((Panel)d).Loaded += new RoutedEventHandler(Panel_Loaded_ErrorBackground);
                }

            }


            static void Panel_Loaded_ErrorBackground(object sender, RoutedEventArgs e)
            {
                DependencyObject d = sender as DependencyObject;

                if (d != null)
                {
                    SetErrorBackgroundOnAllChild(d);
                }

                ((Panel)d).Loaded -= new RoutedEventHandler(Panel_Loaded_ErrorBackground);

                
            }

            private static bool SetErrorBackgroundOnAllChild(DependencyObject d)
            {
                bool results = false;

                if (d != null)
                {
                    Brush value = Validator.GetErrorBackground(d);

                    foreach (DependencyObject curChild in d.GetVisualChildren())
                    {
                        results = true;

                        if ((curChild is TextBox || curChild is Selector))
                        {
                            Validator.SetErrorBackground(curChild, value);
                        }
                    }
                }

                return results;
            
            }

            #endregion

            #region IsEditing

            private static readonly DependencyProperty IsEditingProperty =
                DependencyProperty.RegisterAttached("IsEditing", typeof(bool), typeof(Validator), null);

            /// <summary>
            /// Gets the current datatype associated with the control
            /// </summary>
            /// <param name="d">Dependecy Object / Control</param>
            /// <returns></returns>
            private static bool GetIsEditing(DependencyObject d)
            {
                return (bool)d.GetValue(IsEditingProperty);
            }

            /// <summary>
            /// Sets the Data Type property
            /// </summary>
            /// <param name="d">Dependecy Object / Control</param>
            /// <param name="value">Data Type to be set on the control</param>
            private static void SetIsEditing(DependencyObject d, bool value)
            {
                d.SetValue(IsEditingProperty, value);
            }

            #endregion

            #region RegEx

            public static readonly DependencyProperty RegExProperty =
                    DependencyProperty.RegisterAttached("RegEx", typeof(string), typeof(Validator), null);

            /// <summary>
            /// Gets the current datatype associated with the control
            /// </summary>
            /// <param name="d">Dependecy Object / Control</param>
            /// <returns></returns>
            public static string GetRegEx(DependencyObject d)
            {
                return (string)d.GetValue(RegExProperty);
            }

            /// <summary>
            /// Sets the Data Type property
            /// </summary>
            /// <param name="d">Dependecy Object / Control</param>
            /// <param name="value">Data Type to be set on the control</param>
            public static void SetRegEx(DependencyObject d, string value)
            {
                d.SetValue(RegExProperty, value);
            }

            #endregion

            #region MinValue

            public static readonly DependencyProperty MinValueProperty =
                    DependencyProperty.RegisterAttached("MinValue", typeof(string), typeof(Validator), null);

            /// <summary>
            /// Gets the current datatype associated with the control
            /// </summary>
            /// <param name="d">Dependecy Object / Control</param>
            /// <returns></returns>
            public static string GetMinValue(DependencyObject d)
            {
                return (string)d.GetValue(MinValueProperty);
            }

            /// <summary>
            /// Sets the Data Type property
            /// </summary>
            /// <param name="d">Dependecy Object / Control</param>
            /// <param name="value">Data Type to be set on the control</param>
            public static void SetMinValue(DependencyObject d, string value)
            {
                d.SetValue(MinValueProperty, value);
            }

            #endregion

            #region MaxValue

            public static readonly DependencyProperty MaxValueProperty =
                    DependencyProperty.RegisterAttached("MaxValue", typeof(string), typeof(Validator), null);

            /// <summary>
            /// Gets the current datatype associated with the control
            /// </summary>
            /// <param name="d">Dependecy Object / Control</param>
            /// <returns></returns>
            public static string GetMaxValue(DependencyObject d)
            {
                return (string)d.GetValue(MaxValueProperty);
            }

            /// <summary>
            /// Sets the Data Type property
            /// </summary>
            /// <param name="d">Dependecy Object / Control</param>
            /// <param name="value">Data Type to be set on the control</param>
            public static void SetMaxValue(DependencyObject d, string value)
            {
                d.SetValue(MaxValueProperty, value);
            }

            #endregion

        #endregion

        #region Events
            public static event ValidatingEventHandler Validating;
            public static event ValidatedEventHandler Validated;
        #endregion

            /// <summary>
        /// Event occurs when a key pressed    
        /// </summary>
        /// <param name="sender">Control/Source that raised the event</param>
        /// <param name="e">Event arguments</param>
        private static void textBox_KeyDown(object sender, KeyEventArgs e)
        {
            SetIsEditing((DependencyObject)sender, true);

            // bypass other keys!
            if (IsValidOtherKey(e.Key))
                return;
            //

            DataTypes dataType = GetDataType((DependencyObject)sender);
            TextBox textBox = sender as TextBox;

            if (textBox == null)
                textBox = e.OriginalSource as TextBox;

            switch (dataType)
            {
                case DataTypes.Numeric:
                    e.Handled = !IsNumeric(textBox, e);
                    break;

                case DataTypes.Digit:
                    e.Handled = !IsDigit(e);
                    break;

                case DataTypes.DecimalOnly:
                    e.Handled = !IsDecimal(textBox, e);
                    break;

                case DataTypes.Currency:
                    e.Handled = !IsDecimal(textBox, e);
                    break;

                default:
                    break;
            }
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void textBox_LostFocus(object sender, RoutedEventArgs e)
        {

            SetIsEditing((DependencyObject)sender, false);

            TextBox textBox = sender as TextBox;
            if (textBox == null)
                textBox = e.OriginalSource as TextBox;

            if (textBox != null)
            {
                FormatText(textBox);
                string errorMessage = "";
                ValidateControl(textBox, ref errorMessage);
            }
        }

        private static void textBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (GetIsEditing((DependencyObject)sender))
                return;

            TextBox textBox = sender as TextBox;
            if (textBox == null)
                textBox = e.OriginalSource as TextBox;

            if (textBox != null)
            {

                FormatText(textBox);
            }
        
        }

        private static void FormatText(TextBox textBox)
        {
            DataTypes dataType = GetDataType((DependencyObject)textBox);

            string displayFormat = CustomFormatProvider.GetDisplayFormat(dataType);

            //Format the output
            textBox.Text = String.Format(new CustomFormatProvider(), "{0:" + displayFormat + "}", textBox.Text);


            //switch (dataType)
            //{
            //    case DataTypes.Currency:
            //        decimal result = 0;
            //        if (textBox.Text.Trim().Length > 0)
            //            Decimal.TryParse(textBox.Text, System.Globalization.NumberStyles.Currency, System.Globalization.NumberFormatInfo.CurrentInfo, out result);

            //        textBox.Text = string.Format("{0:c2}", result);
            //        break;

            //    case DataTypes.SSN:

            //    default:
            //        break;
            //}
        
        }
        
        /// <summary>
        /// 
        /// </summary>
        /// <param name="controlToValidate"></param>
        /// <returns>return the error message for a control, or "" if no error</returns>
        private static string GetErrorMessage(Control controlToValidate)
        {
            string errorMessage = "";

            //If NOT Enabled OR ReadOnly is True then do NOT validate the data.
            if ((!controlToValidate.IsEnabled) || (controlToValidate is TextBox && ((TextBox)controlToValidate).IsReadOnly))
                return "";



            string displayName = GetDisplayName(controlToValidate);
            DataTypes dataType = GetDataType((DependencyObject)controlToValidate);

            string value = null;
            if (controlToValidate is TextBox)
            {
                value = ((TextBox)controlToValidate).Text;

                if (! CustomFormatProvider.IsDataValid(value, dataType, displayName, ref errorMessage))
                    return errorMessage;

                // If Required is true and TextBoxBase is empty, 
                // then return validation error. If not required,
                // it's OK to be empty, and don't check anything else.
                if (value.Length == 0)
                {
                    if (GetIsRequired(controlToValidate))
                        return string.Format(Resources.Validator_Required, displayName);
                    else // validate against custom ValidatingEventHandler
                    {
                        return GetValidatingEventHandlerMessage(controlToValidate);
                    }
                }

                //Get the raw text
                string strUnFormat = CustomFormatProvider.CUSTOM_UNFORMAT_INDICATOR + CustomFormatProvider.GetDisplayFormat(dataType).Trim(CustomFormatProvider.CUSTOM_FORMAT_INDICATOR.ToCharArray());
                value = string.Format(new CustomFormatProvider(), "{0:" + strUnFormat + "}", value);

            
            }
            else if (controlToValidate is Selector)
            {
                // If Required is true and none of the items are selected,
                // then return validation error. If not required,
                // it's OK to be empty/non-selected, and don't check anything else.
                if (((Selector)controlToValidate).SelectedIndex < 0)
                {
                    if (GetIsRequired(controlToValidate))
                    {
                        return string.Format(Resources.Validator_Required, displayName);
                    }
                }

                // validate against custom ValidatingEventHandler
                return GetValidatingEventHandlerMessage(controlToValidate);
            
            }


            bool blnCustomDateString = false;
            //This flag is used to check if ?/?/? and */*/* exists
            //If the flag is true then dont validate with MIN and MAX values

            Type dataTypeOfDisplayType = CustomFormatProvider.GetDataTypeOfDisplayType(dataType);

            //Consider ?/?/? and */*/* for dates
            if (object.ReferenceEquals(dataTypeOfDisplayType, typeof(System.DateTime)) || object.ReferenceEquals(dataTypeOfDisplayType, typeof(DateTime)))
            {
                //If ? OR *
                if (!Utilities.IsDate(value))
                {
                    //Get the corresponding date value
                    blnCustomDateString = true;
                    value = CustomFormatProvider.GetValue(value, dataType).ToString();
                }
            }

            // validate against the RegularExpression property
            string regEx = GetRegEx(controlToValidate);
            if (regEx != null && regEx.Length > 0)
            {
                // note that we must enclose the regex between ^ and $
                if (!System.Text.RegularExpressions.Regex.IsMatch(value, "^" + regEx + "$"))
                {
                    return string.Format(Resources.Validator_RegExError, displayName);
                }
            }


            string minValue = GetMinValue(controlToValidate);
            string maxValue = GetMaxValue(controlToValidate);
            bool blnErrorFound = false;
            
            // validate against the MinValue and MaxValue property
            if (!blnCustomDateString && minValue != null && minValue.Length > 0)
            {
                // perform type-agnostic comparison
                blnErrorFound = false;

                if (object.ReferenceEquals(dataTypeOfDisplayType, typeof(string)))
                {
                    if (string.CompareOrdinal(value, minValue) < 0)
                    {
                        blnErrorFound = true;
                    }
                }

                else if (object.ReferenceEquals(dataTypeOfDisplayType, typeof(System.DateTime)) || object.ReferenceEquals(dataTypeOfDisplayType, typeof(DateTime)))
                {
                    if (Convert.ToDateTime(value) < Convert.ToDateTime(minValue))
                    {
                        blnErrorFound = true;
                    }
                }

                else
                {
                    if (Convert.ToDecimal(value) < Convert.ToDecimal(minValue))
                    {
                        blnErrorFound = true;
                    }
                }

                if (blnErrorFound)
                {
                    //Check if the max value is specified so that you can show a common error message
                    if (maxValue != null && maxValue.Length > 0)
                    {
                        return string.Format(Resources.Validator_MinMaxValueError, displayName, minValue, maxValue);
                    }
                    else
                    {
                        return string.Format(Resources.Validator_MinValueError, displayName, minValue);
                    }
                }
            }



            // validate against the MaxValue property
            if (!blnCustomDateString && maxValue != null && maxValue.Length > 0)
            {
                // perform type-agnostic comparison
                blnErrorFound = false;

                if (object.ReferenceEquals(dataTypeOfDisplayType, typeof(string)))
                {
                    if (string.CompareOrdinal(value, maxValue) > 0)
                    {
                        blnErrorFound = true;
                    }
                }

                else if (object.ReferenceEquals(dataTypeOfDisplayType, typeof(System.DateTime)) || object.ReferenceEquals(dataTypeOfDisplayType, typeof(DateTime)))
                {
                    if (Convert.ToDateTime(value) > Convert.ToDateTime(maxValue))
                    {
                        blnErrorFound = true;
                    }
                }

                else
                {
                    if (Convert.ToDecimal(value) > Convert.ToDecimal(maxValue))
                    {
                        blnErrorFound = true;
                    }
                }

                if (blnErrorFound)
                {
                    //Check if the max value is specified so that you can show a common error message
                    if (minValue != null && minValue.Length > 0)
                    {
                        return string.Format(Resources.Validator_MinMaxValueError, displayName, minValue, maxValue);
                    }
                    else
                    {
                        return string.Format(Resources.Validator_MaxValueError, displayName, maxValue);
                    }
                }
            }

            return GetValidatingEventHandlerMessage(controlToValidate);

            //return errorMessage;



        }

        private static string GetValidatingEventHandlerMessage(Control controlToValidate)
        {
            if (Validating != null)
            {
                ValidatingEventArgs e = new ValidatingEventArgs(controlToValidate);
                Validating(controlToValidate, e);

                if (!e.IsValid)
                    return e.ErrorMessage;
            }

            return string.Empty;


        }

        //private string GetValidatingEventHandlerMessage(Control controlToValidate)
        //{
        //    // validate against custom ValidatingEventHandler
        //    if (this.Validating != null)
        //    {
        //        ValidatingEventArgs e = new ValidatingEventArgs(controlToValidate);
        //        this.OnValidating(e);

        //        if (!e.IsValid)
        //            return e.ErrorMessage;

        //    }


        //    return string.Empty;

        //}


        //protected virtual void OnValidating(ValidatingEventArgs e)
        //{
        //    ValidatingEventHandler ValidatingEvent = this.Validating;

        //    if (ValidatingEvent != null)
        //    {
        //        ValidatingEvent(this, e);
        //    }
        //}


        //protected virtual void OnValidated(ValidatedEventArgs e)
        //{
        //    ValidatedEventHandler ValidatedEvent = this.Validated;

        //    if (ValidatedEvent != null)
        //    {
        //        ValidatedEvent(this, e);
        //    }
        //}

        /// <summary>
        /// 
        /// </summary>
        /// <param name="controlToValidate"></param>
        /// <param name="errorMessage"></param>
        /// <returns></returns>
        public static bool ValidateControl(Control controlToValidate, ref string errorMessage)
        {

            // Fetch the error message - it may be empty, which means no error.
            errorMessage = GetErrorMessage(controlToValidate);

            if (errorMessage.Length > 0) //Change the background color and tooltip if any error.
            {

                ErrorProvider.SetErrorMessage(controlToValidate, errorMessage);

                if (GetLastBackground(controlToValidate) == null) //If the control is NOT in error state yet
                {
                    SetLastBackground(controlToValidate, controlToValidate.Background);

                    controlToValidate.Background = GetErrorBackground(controlToValidate); //new SolidColorBrush(Colors.Red);
                }
            }
            else //Reset the background color and tooltip since the error is resolved.
            {

                controlToValidate.ClearValue(ErrorProvider.ErrorMessageProperty);
                
                if (GetLastBackground(controlToValidate) != null) //If the control was in error state
                {
                    controlToValidate.Background = GetLastBackground(controlToValidate);
                    SetLastBackground(controlToValidate, null);
                }
            
            }

            if (Validated != null)
            {
                ValidatedEventArgs e = new ValidatedEventArgs(controlToValidate, (errorMessage.Length == 0), errorMessage);
                Validated(controlToValidate, e);

            }

            if (errorMessage.Length == 0)
                return true;
            else
                return false;

        }

        public static bool ValidateContainer(DependencyObject containerControl)
        {
            List<InvalidControl> invalidControls = new List<InvalidControl>();
            return ValidateContainer(containerControl, ref invalidControls);
        }

        public static bool ValidateContainer(DependencyObject containerControl, ref List<InvalidControl> invalidControls)
        {

            bool blnSuccess = ValidateAllChildControls(containerControl, ref invalidControls);
           
            if (!blnSuccess  )
            {
                ValidationSummary.DisplayValidationSummary(containerControl, invalidControls);
                //this.ValidationSummaryProvider.DisplayValidationSummary(this, containerControl, invalidControls);
            }
           
            return blnSuccess;
           
        }

        // validate all the controls in the containerControl passed
        private static bool ValidateAllChildControls(DependencyObject parentControl, ref List<InvalidControl> invalidControls)
        {
 
            bool blnSuccess = true;

            if (parentControl is Control && GetDataType(parentControl) != DataTypes.None) 
            {
                string errorMessage = "";
                Control controlToValidate = parentControl as Control;
                if (!ValidateControl(controlToValidate, ref errorMessage))
                {
                    if ((invalidControls != null))
                    {
                        invalidControls.Add(new InvalidControl(controlToValidate, controlToValidate.TabIndex, errorMessage));
                    }
                
                    blnSuccess = false;
                }
            }

            foreach (DependencyObject curChild in parentControl.GetVisualChildren())
            {
                if (curChild is Control)
                {
                    if (!ValidateAllChildControls(curChild as Control, ref invalidControls))
                        blnSuccess = false;
                }
            }

            return blnSuccess;

        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        private static bool IsValidOtherKey(Key key)
        {
            //Control key
            if ((Keyboard.Modifiers & ModifierKeys.Control) != 0)
                return true;

            // Allow the foll keys:
            // Back, Tab, Shift, Enter, Ctrl, Alt, CapsLock, Escape, PageUp, PageDown
            // End, Home, Up, Right, Left, Down, Insert, Delete 
            // except for space!
            // allow all Fx keys
            if (
                (key < Key.D0 && key != Key.Space)
                || (key > Key.Z && key < Key.NumPad0))
            {
                return true;
            }
            // we need to examine all others!
            return false;
        }


        private static bool IsDigit(KeyEventArgs e)
        {
            if (((e.Key >= Key.D0 && e.Key <= Key.D9) || (e.Key >= Key.NumPad0 && e.Key <= Key.NumPad9)) && Keyboard.Modifiers == ModifierKeys.None)
                return true;
            else
                return false;

        }//end of method


        private static bool IsNumeric(object sender, KeyEventArgs e)
        {

            if (IsDigit(e))
            {
                //If zero check that its not the first character being entered
                if ((e.Key == Key.D0 || e.Key == Key.NumPad0) && sender is TextBox)
                {

                    TextBox textBox = sender as TextBox;

                    if ((textBox.SelectionStart <= 0 && textBox.SelectionLength < textBox.Text.Length) ||
                         (textBox.SelectionStart == 1 && textBox.Text.StartsWith("0")))
                        return false;
                    else
                        return true;

                }
                else
                    return true;

            }
            //If negative check that its allowed and it is the first character being entered
            else if (e.Key == Key.Subtract || (e.Key == Key.Unknown && e.PlatformKeyCode == 189))
            {
                //If negative is not allowed return false
                if (!GetNegativeAllowed((DependencyObject)sender))
                    return false;

                if (sender is TextBox)
                {
                    TextBox textBox = sender as TextBox;

                    //Ensure that negative is the first character being entered
                    if ((textBox.SelectionStart == 0) && (textBox.SelectionLength == textBox.Text.Length || (textBox.Text.IndexOf("-") < textBox.SelectionLength)))
                        return true;
                    else
                        return false;

                }
                else
                    return true;
            }
            else
                return false;

        }//end of method

        private static bool IsDecimalPoint(object sender, KeyEventArgs e)
        {

            //Check if decimal point was entered 
            if ((e.Key == Key.Decimal && Keyboard.Modifiers == ModifierKeys.None) || (e.Key == Key.Unknown && e.PlatformKeyCode == 190))
            {
                //Ensure that there is no existing decimal
                if (sender is TextBox)
                {
                    TextBox textBox = sender as TextBox;

                    if (textBox.Text.Contains(".") && textBox.SelectionLength != textBox.Text.Length)
                        return false;
                    else
                        return true;
                }
                else
                    return true;
            }
            else
                return false;


        }//end of method


        private static bool IsDecimal(object sender, KeyEventArgs e)
        {

            if (IsNumeric(sender, e) || IsDecimalPoint(sender, e))
                return true;
            else
                return false;

        }//end of method





    }
}
